From 36f104159fa2d62a2d9614c3f01265479b88e98f Mon Sep 17 00:00:00 2001 From: tsteven4 <13596209+tsteven4@users.noreply.github.com> Date: Tue, 2 Aug 2022 08:15:25 -0600 Subject: [PATCH] use xmlstreamwriter with osm format (#901) * convert osm writer use xmlstreamwriter * use xmlstreamwriter for osm. * add missing reference files for osm test. * fix time zone test issues with osm writer test. * use writeEmptyElement in osm writer --- defs.h | 2 +- osm.cc | 143 +++++++++++----------- osm.h | 24 ++-- reference/osm-center-out.xml | 137 +++++++++++++++++++++ reference/osm-out.xml | 206 +++++++++++++++++++++++++++++++ reference/osm_writer.csv | 21 ++++ reference/osm_writer.xml | 227 +++++++++++++++++++++++++++++++++++ testo.d/osm.test | 7 ++ util.cc | 2 +- 9 files changed, 687 insertions(+), 82 deletions(-) create mode 100644 reference/osm-center-out.xml create mode 100644 reference/osm-out.xml create mode 100644 reference/osm_writer.csv create mode 100644 reference/osm_writer.xml diff --git a/defs.h b/defs.h index ef58e39fc..b7d1fc246 100644 --- a/defs.h +++ b/defs.h @@ -1079,7 +1079,7 @@ QDateTime dotnet_time_to_qdatetime(long long dotnet); QString get_cache_icon(const Waypoint* waypointp); QString gs_get_cachetype(geocache_type t); QString gs_get_container(geocache_container t); -QString xml_entitize(const QString& str); +[[deprecated("Use xmlstreamwriter.")]] QString xml_entitize(const QString& str); QString html_entitize(const QString& str); QString strip_html(const utf_string*); QString strip_nastyhtml(const QString& in); diff --git a/osm.cc b/osm.cc index b4ba32613..070b69f6f 100644 --- a/osm.cc +++ b/osm.cc @@ -20,21 +20,21 @@ */ -#include // for strlen, strchr, strcmp +#include // for strlen, strchr, st -#include // for QByteArray -#include // for QHash -#include // for QLatin1String -#include // for QPair, operator== -#include // for QString, operator==, operator+ -#include // for QXmlStreamAttributes -#include // for qPrintable, QAddConst<>::Type +#include // for QByteArray +#include // for operator|, QIODevice, QIODevice::Text, QIODevice::WriteOnly +#include // for QLatin1String +#include // for QPair, operator== +#include // for QString, operator==, operator+ +#include // for QXmlStreamAttributes +#include // for qMax, qPrintable #include "defs.h" #include "osm.h" -#include "gbfile.h" // for gbfprintf, gbfclose, gbfopen -#include "src/core/datetime.h" // for DateTime -#include "xmlgeneric.h" // for xg_string, build_xg_tag_map, xml_deinit, xml_init, xml_read +#include "src/core/datetime.h" // for DateTime +#include "src/core/xmlstreamwriter.h" // for XmlStreamWriter +#include "xmlgeneric.h" // for xg_string, build_xg_tag_map, xml_deinit, xml_init, xml_read #define MYNAME "osm" @@ -652,9 +652,9 @@ void OsmFormat::osm_write_tag(const QString& key, const QString& value) const { if (!value.isEmpty()) { - gbfputs(QStringLiteral(" \n") - .arg(key, xml_entitize(value)), - fout); + fout->writeEmptyElement(QStringLiteral("tag")); + fout->writeAttribute(QStringLiteral("k"), key); + fout->writeAttribute(QStringLiteral("v"), value); } } @@ -668,32 +668,15 @@ OsmFormat::osm_disp_feature(const Waypoint* waypoint) const } void -OsmFormat::osm_write_opt_tag(const char* atag) +OsmFormat::osm_write_opt_tag(const QString& atag) { - char* cin; - - if (!atag) { - return; - } - - char* tag = cin = xstrdup(atag); - char* ce = cin + strlen(cin); - - while (cin < ce) { - char* sc, *dp; - - if ((sc = strchr(cin, ';'))) { - *sc = '\0'; + const QStringList tags = atag.split(';'); + for (const auto& tag : tags) { + auto idx = tag.indexOf(':'); + if (idx >= 0) { + osm_write_tag(tag.left(idx), tag.mid(idx+1)); } - - if ((dp = strchr(cin, ':'))) { - *dp++ = '\0'; - osm_write_tag(cin, dp); - } - cin += strlen(cin) + 1; } - - xfree(tag); } void @@ -730,41 +713,43 @@ OsmFormat::osm_waypt_disp(const Waypoint* waypoint) *id = --node_id; const_cast(waypoint)->extra_data = id; - gbfprintf(fout, " latitude, waypoint->longitude); + fout->writeStartElement(QStringLiteral("node")); + fout->writeAttribute(QStringLiteral("id"), QString::number(*id)); + fout->writeAttribute(QStringLiteral("visible"), QStringLiteral("true")); + fout->writeAttribute(QStringLiteral("lat"), QString::number(waypoint->latitude, 'f', 7)); + fout->writeAttribute(QStringLiteral("lon"), QString::number(waypoint->longitude, 'f', 7)); if (waypoint->creation_time.isValid()) { - QString time_string = waypoint->CreationTimeXML(); - gbfprintf(fout, " timestamp='%s'", qPrintable(time_string)); + fout->writeAttribute(QStringLiteral("timestamp"), waypoint->CreationTimeXML()); } - gbfprintf(fout, ">\n"); if (waypoint->hdop) { - gbfprintf(fout, " \n", waypoint->hdop); + osm_write_tag(QStringLiteral("gps:hdop"), QString::number(waypoint->hdop, 'f')); } if (waypoint->vdop) { - gbfprintf(fout, " \n", waypoint->vdop); + osm_write_tag(QStringLiteral("gps:vdop"), QString::number(waypoint->vdop, 'f')); } if (waypoint->pdop) { - gbfprintf(fout, " \n", waypoint->pdop); + osm_write_tag(QStringLiteral("gps:pdop"), QString::number(waypoint->pdop, 'f')); } if (waypoint->sat > 0) { - gbfprintf(fout, " \n", waypoint->sat); + osm_write_tag(QStringLiteral("gps:sat"), QString::number(waypoint->sat)); } switch (waypoint->fix) { case fix_2d: - gbfprintf(fout, " \n"); + osm_write_tag(QStringLiteral("gps:fix"), QStringLiteral("2d")); break; case fix_3d: - gbfprintf(fout, " \n"); + osm_write_tag(QStringLiteral("gps:fix"), QStringLiteral("3d")); break; case fix_dgps: - gbfprintf(fout, " \n"); + osm_write_tag(QStringLiteral("gps:fix"), QStringLiteral("dgps")); break; case fix_pps: - gbfprintf(fout, " \n"); + osm_write_tag(QStringLiteral("gps:fix"), QStringLiteral("pps")); break; case fix_none: - gbfprintf(fout, " \n"); + osm_write_tag(QStringLiteral("gps:fix"), QStringLiteral("none")); break; case fix_unknown: default: @@ -772,12 +757,14 @@ OsmFormat::osm_waypt_disp(const Waypoint* waypoint) } if (strlen(created_by) !=0) { - gbfprintf(fout, " \n"); + } + osm_write_tag(QStringLiteral("created_by"), value); } osm_write_tag("name", waypoint->shortname); @@ -788,7 +775,7 @@ OsmFormat::osm_waypt_disp(const Waypoint* waypoint) osm_write_opt_tag(opt_tagnd); - gbfprintf(fout, " \n"); + fout->writeEndElement(); // node } void @@ -800,7 +787,9 @@ OsmFormat::osm_rte_disp_head(const route_head* route) return; } - gbfprintf(fout, " \n", --node_id); + fout->writeStartElement(QStringLiteral("way")); + fout->writeAttribute(QStringLiteral("id"), QString::number(--node_id)); + fout->writeAttribute(QStringLiteral("visible"), QStringLiteral("true")); } void @@ -815,7 +804,8 @@ OsmFormat::osm_rtept_disp(const Waypoint* wpt_ref) const if (waypoints.contains(name)) { const Waypoint* waypoint = waypoints.value(name); auto* id = static_cast(waypoint->extra_data); - gbfprintf(fout, " \n", *id); + fout->writeEmptyElement(QStringLiteral("nd")); + fout->writeAttribute(QStringLiteral("ref"), QString::number(*id)); } } @@ -827,12 +817,14 @@ OsmFormat::osm_rte_disp_trail(const route_head* route) } if (strlen(created_by) !=0) { - gbfprintf(fout, " \n"); + } + osm_write_tag(QStringLiteral("created_by"), value); } osm_write_tag("name", route->rte_name); @@ -842,7 +834,7 @@ OsmFormat::osm_rte_disp_trail(const route_head* route) osm_write_opt_tag(opt_tag); } - gbfprintf(fout, " \n"); + fout->writeEndElement(); // way } /*-----------------------------------------------------------------------------*/ @@ -850,7 +842,12 @@ OsmFormat::osm_rte_disp_trail(const route_head* route) void OsmFormat::wr_init(const QString& fname) { - fout = gbfopen(fname, "w", MYNAME); + ofile = new gpsbabel::File(fname); + ofile->open(QIODevice::WriteOnly | QIODevice::Text); + + fout = new gpsbabel::XmlStreamWriter(ofile); + fout->setAutoFormatting(true); + fout->setAutoFormattingIndent(2); osm_init_icons(); waypoints.clear(); @@ -860,12 +857,15 @@ OsmFormat::wr_init(const QString& fname) void OsmFormat::write() { - gbfprintf(fout, "\n"); - gbfprintf(fout, "\n"); + fout->writeAttribute(QStringLiteral("generator"), value); auto osm_waypt_disp_lambda = [this](const Waypoint* waypointp)->void { osm_waypt_disp(waypointp); @@ -886,13 +886,18 @@ OsmFormat::write() route_disp_all(osm_rte_disp_head_lambda, osm_rte_disp_trail_lambda, osm_rtept_disp_lambda); track_disp_all(osm_rte_disp_head_lambda, osm_rte_disp_trail_lambda, osm_rtept_disp_lambda); - gbfprintf(fout, "\n"); + fout->writeEndElement(); // osm } void OsmFormat::wr_deinit() { - gbfclose(fout); + fout->writeEndDocument(); + delete fout; + fout = nullptr; + ofile->close(); + delete ofile; + ofile = nullptr; waypt_disp_all(osm_release_ids); route_disp_all(nullptr, nullptr, osm_release_ids); diff --git a/osm.h b/osm.h index 89996399b..9cf6d1477 100644 --- a/osm.h +++ b/osm.h @@ -22,17 +22,18 @@ #ifndef OSM_H_INCLUDED_ #define OSM_H_INCLUDED_ -#include // for QHash -#include // for QList -#include // for QPair -#include // for QString -#include // for QVector -#include // for QXmlStreamAttributes +#include // for QHash +#include // for QList +#include // for QPair +#include // for QString +#include // for QVector +#include // for QXmlStreamAttributes #include "defs.h" -#include "format.h" // for Format -#include "gbfile.h" // for gbfile -#include "xmlgeneric.h" // for xg_functor_map_entry, cb_start, cb_end, xg_string +#include "format.h" // for Format +#include "src/core/file.h" // for File +#include "src/core/xmlstreamwriter.h" // for XmlStreamWriter +#include "xmlgeneric.h" // for xg_functor_map_entry, cb_start, cb_end, xg_string class OsmFormat : public Format @@ -109,7 +110,7 @@ private: void osm_init_icons(); void osm_write_tag(const QString& key, const QString& value) const; void osm_disp_feature(const Waypoint* waypoint) const; - void osm_write_opt_tag(const char* atag); + void osm_write_opt_tag(const QString& atag); static void osm_release_ids(const Waypoint* waypoint); static QString osm_name_from_wpt(const Waypoint* waypoint); void osm_waypt_disp(const Waypoint* waypoint); @@ -135,7 +136,8 @@ private: QHash, const osm_icon_mapping_t*> values; QHash icons; - gbfile* fout{}; + gpsbabel::File* ofile{nullptr}; + gpsbabel::XmlStreamWriter* fout{nullptr}; int node_id{}; int skip_rte{}; diff --git a/reference/osm-center-out.xml b/reference/osm-center-out.xml new file mode 100644 index 000000000..e3fec4858 --- /dev/null +++ b/reference/osm-center-out.xml @@ -0,0 +1,137 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/reference/osm-out.xml b/reference/osm-out.xml new file mode 100644 index 000000000..e80d88a07 --- /dev/null +++ b/reference/osm-out.xml @@ -0,0 +1,206 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/reference/osm_writer.csv b/reference/osm_writer.csv new file mode 100644 index 000000000..34115f72b --- /dev/null +++ b/reference/osm_writer.csv @@ -0,0 +1,21 @@ +No,Name,Latitude,Longitude,Altitude,Speed,Course,HDOP,VDOP,Satellites,Fix,Date,Time +1,"TPT000""",40.741192,-88.737399,225.0,29.25,359.0,0.88,1.50,11,2d,2009/07/06,15:14:11 +2,TPT001&,40.741454,-88.737408,225.0,29.25,358.6,0.88,1.50,11,3d,2009/07/06,15:14:12 +3,TPT002',40.741717,-88.737415,226.0,29.23,358.7,0.88,1.50,11,dgps,2009/07/06,15:14:13 +4,TPT003<,40.741978,-88.737423,226.0,29.23,358.7,0.88,1.50,11,pps,2009/07/06,15:14:14 +5,TPT004>,40.742238,-88.737431,226.0,29.20,358.7,0.88,1.50,11,none,2009/07/06,15:14:15 +6,TPT005,40.742500,-88.737439,226.0,29.23,358.6,0.88,1.50,11,2d,2009/07/06,15:14:16 +7,TPT006,40.742763,-88.737447,226.0,29.23,358.7,0.88,1.50,11,2d,2009/07/06,15:14:17 +8,TPT007,40.743024,-88.737453,226.0,29.25,358.8,0.88,1.50,11,2d,2009/07/06,15:14:18 +9,TPT008,40.743286,-88.737461,226.0,29.25,358.8,0.88,1.50,11,2d,2009/07/06,15:14:19 +10,TPT009,40.743548,-88.737467,227.0,29.25,358.7,0.88,1.50,11,2d,2009/07/06,15:14:20 +11,TPT010,40.743810,-88.737475,227.0,29.28,358.9,0.88,1.50,11,2d,2009/07/06,15:14:21 +12,TPT011,40.744072,-88.737479,227.0,29.28,359.2,0.88,1.50,11,2d,2009/07/06,15:14:22 +13,TPT012,40.744334,-88.737484,227.0,29.28,359.2,0.88,1.50,11,2d,2009/07/06,15:14:23 +14,TPT013,40.744596,-88.737489,227.0,29.25,359.1,0.88,1.50,11,2d,2009/07/06,15:14:24 +15,TPT014,40.744858,-88.737495,227.0,29.23,359.0,0.88,1.50,11,2d,2009/07/06,15:14:25 +16,TPT015,40.745120,-88.737500,227.0,29.28,359.1,0.88,1.50,11,2d,2009/07/06,15:14:26 +17,TPT016,40.745383,-88.737503,227.0,29.36,359.5,0.88,1.50,11,2d,2009/07/06,15:14:27 +18,TPT017,40.745647,-88.737502,227.0,29.39,0.3,0.88,1.50,11,2d,2009/07/06,15:14:28 +19,TPT018,40.745909,-88.737491,227.0,29.36,1.9,0.88,1.50,11,2d,2009/07/06,15:14:29 +20,TPT019,40.746172,-88.737470,227.0,29.36,3.5,0.88,1.50,11,2d,2009/07/06,15:14:30 diff --git a/reference/osm_writer.xml b/reference/osm_writer.xml new file mode 100644 index 000000000..a833f1ea0 --- /dev/null +++ b/reference/osm_writer.xml @@ -0,0 +1,227 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/testo.d/osm.test b/testo.d/osm.test index d2cab0fa1..de630b7b4 100644 --- a/testo.d/osm.test +++ b/testo.d/osm.test @@ -3,9 +3,16 @@ rm -f ${TMPDIR}/osm-* gpsbabel -i osm -f ${REFERENCE}/osm-data.xml -o gpx -F ${TMPDIR}/osm-data.gpx -o osm -F ${TMPDIR}/osm-out.xml compare ${REFERENCE}/osm-data.gpx ${TMPDIR}/osm-data.gpx +compare ${REFERENCE}/osm-out.xml ${TMPDIR}/osm-out.xml gpsbabel -i osm -f ${REFERENCE}/osm-center-data.xml -o gpx -F ${TMPDIR}/osm-center-data.gpx -o osm -F ${TMPDIR}/osm-center-out.xml compare ${REFERENCE}/osm-center-data.gpx ${TMPDIR}/osm-center-data.gpx +compare ${REFERENCE}/osm-center-out.xml ${TMPDIR}/osm-center-out.xml # FIXME: implement a test for OSM writer, if possible. # compare ${REFERENCE}/osm-data.xml ${TMPDIR}/osm-out.xml + +# OK, we can't compare our output to osm generated reference files, but at least make sure we produce consistent output +gpsbabel -t -i unicsv,utc=0 -f ${REFERENCE}/osm_writer.csv -o osm,tagnd="amenity:pub;building:yes",tag="highway:motorway" -F ${TMPDIR}/osm_writer.xml +compare ${REFERENCE}/osm_writer.xml ${TMPDIR}/osm_writer.xml + diff --git a/util.cc b/util.cc index 3eb7ab4b6..02ecbd53c 100644 --- a/util.cc +++ b/util.cc @@ -1458,7 +1458,7 @@ entitize(const char* str, bool is_html) * Public callers for the above to hide the absence of &apos from HTML */ -QString xml_entitize(const QString& str) +[[deprecated("Use xmlstreamwriter.")]] QString xml_entitize(const QString& str) { return entitize(CSTR(str), false); } -- 2.30.2